#include "includes/util.h"
#include <png.h>
#include <unistd.h>
#include <stdlib.h>

GLuint util_load_texture(const char * path){
	
	int i;
	
	// Identifiant de la texture png
	GLuint texture;
	
	// Pointeur vers le flux vers le fichier
	png_FILE_p file;
	
	// Pour le nombre magique dans le but de savoir si le fichier charge est bien un PNG
	png_byte png_test[8];

	// Structure decrivant le PNG
	png_structp png;
	
	// Infos sur le PNG
	png_infop info;
	
	// Tableau de pixels pour creer la texture
	GLubyte * pixels;
	
	// Tableau contenant les pointeurs vers les debuts de chaque ligne
	png_bytepp rows;
	
	// Ouverture du fichier
	file = fopen(path, "rb");
	
	// Si echec lors de l'ouverture
	if(!file){
		fprintf(stderr, "Echec lors de l'ouverture de %s\n", path);
		exit(1);
	}
	
	// On lit les 8 premiers octets pour voir s'il s'agit d'une image PNG
	fread(png_test, 1, sizeof(png_test), file);
	
	// On verifie les octets lus pour savoir si l'image est un PNG
	if(!png_check_sig(png_test, sizeof(png_test))){
		fprintf(stderr, "Image non PNG : %s\n", path);
		fclose(file);
		exit(1);
	}
	
	// Creation d'un contexte pour la lecture du PNG
	png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	
	// Si echec de la creation du contexte
	if(!png){
		fprintf(stderr, "Echec de la creation du contexte de lecture de %s\n", path);
		fclose(file);
		exit(1);
	}
	
	// Creation d'un contexte pour les infos du PNG
	info = png_create_info_struct(png);
	
	// Si echec de la creation du contexte pour les infos
	if(!info){
		fprintf(stderr, "Echec de la creation du contexte pour les infos de %s\n", path);
		png_destroy_read_struct(&png, NULL, NULL);
		exit(1);
	}
	
	// La librairie utilise le fichier ouvert.
	png_init_io(png, file);

	// On decale la lecture apres le png_test deja lu
	png_set_sig_bytes(png, sizeof(png_test));
	
	png_read_info(png,info);
	
	if(png_get_color_type(png, info) != PNG_COLOR_TYPE_RGB_ALPHA){
		fprintf(stderr, "Type de png non gere (<> RGBA sans palette) : %s\n", path);
		png_destroy_read_struct(&png, &info, NULL);
		exit(1);
	}
	
	// On alloue la memoire necessaire pour les pixels
	pixels = (GLubyte*) malloc(sizeof(GLubyte) * UTIL_PNG_FORMAT * info->width * info->height);
	
	// Allocation de la memoire pour les adresses des debuts de ligne
	rows = (png_bytepp) malloc(sizeof(png_bytep) * info->height);
	
	// On met les debuts de ligne dans le tableau
	for(i = 0; i < info->height; i++){
		rows[i] = (png_bytep) (pixels + ((info->height - (i+1)) * UTIL_PNG_FORMAT * info->width));
	}

	// Lancement de la lecture de l'image
	png_read_image(png, rows);

	// Demande la terminaison de la lecture
	png_read_end(png, NULL);
	
	// On genere un identifiant de texture OpenGL
	glGenTextures(1, &texture);
	
	// On declare la texture comme texture 2D OpenGL
	glBindTexture(GL_TEXTURE_2D, texture);
	
	// On applique la carte de pixels a l'identifiant de la texture
	glTexImage2D(GL_TEXTURE_2D, 0, UTIL_PNG_FORMAT, info->width, info->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
	
	// Rendre la texture lineaire
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	
	// On libere le tableau de pixels
	free(pixels);
	
	// Liberation des ressources
	png_destroy_read_struct(&png, &info, NULL);
	free(rows);
	fclose(file);
	
	// On retourne l'identifiant de la texture
	return texture;
}


void util_display_texture(GLuint texture, GLfloat x, GLfloat y, GLfloat width, GLfloat height){
	
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texture);
	glBegin(GL_QUADS);
		glTexCoord2i(0,0);glVertex2f(x, y);
		glTexCoord2i(0,1);glVertex2f(x, y + height);
		glTexCoord2i(1,1);glVertex2f(x + width, y + height);
		glTexCoord2i(1,0);glVertex2f(x + width, y);
	glEnd();
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
}
